package com.iot08.admin.service;

import com.iot08.admin.service.page.PageVO;
import com.iot08.admin.service.page.PageableImpl;
import com.iot08.admin.utils.ExcelUtil;
import com.iot08.common.config.redis.RedisService;
import com.iot08.common.constant.Const;
import com.iot08.common.entity.admin.ChannelArea;
import com.iot08.common.entity.admin.SysUser;
import com.iot08.common.entity.app.CanCheckPosition;
import com.iot08.common.entity.app.Device;
import com.iot08.common.response.Response;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.CollectionUtil;
import com.iot08.common.utils.RegexUtil;
import com.iot08.common.utils.StringUtil;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @version 1.0
 * @Description:
 * @time: 2020/10/17 8:44
 * @author: Rock
 */
@Service
public class CanCheckPositionService extends BaseService<CanCheckPosition> {

    @Resource
    private DeviceService deviceService;
    @Resource
    private ChannelAreaService channelAreaService;
    @Resource
    private OperationService operationService;
    @Resource
    private RedisService redisService;

    /**
     * 根据 User 获取设备位置分布数据列表
     * @param page
     * @param user
     * @time: 2020/10/30 16:19
     * @author: Rock
     * @version 1.0
     */
    public Page<CanCheckPosition> list(PageVO page, SysUser user) {
        PageableImpl pageable = new PageableImpl();
        page.setSort(Sort.by(Sort.Order.desc("_id")));
        pageable.setPage(page);
        Criteria criteria = new Criteria();
        if (StringUtils.isNotEmpty(page.getSearchValue())) {
            criteria.and("_id").is(page.getSearchValue());
        }
        Integer userAreaLevel = 0;
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            userAreaLevel = user.getChannelArea() == null ? 1 : user.getChannelArea().getLevel();
            if (userAreaLevel == 1) {
                criteria.andOperator(Criteria.where("agent_code").in(CollectionUtil.longToStr(user.getChannelAff().getChannelCodes())));
            } else {
                List<String> channelIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
                criteria.andOperator(Criteria.where("channel_area_id").in(channelIdList));
            }
        }
        Query query = new Query().addCriteria(criteria);
        long count = mongoTemplate.count(query, CanCheckPosition.class);
        page.setTotalResult((int) count);
        List<CanCheckPosition> list = mongoTemplate.find(query.with(pageable), CanCheckPosition.class);
        for (CanCheckPosition position : list) {
            Device device = deviceService.findById(position.getId());
            if (device != null && device.getNowloc() != null && device.getNowloc().get("timestamp") instanceof Double) {
                device.getNowloc().put("timestamp", ((Double) device.getNowloc().get("timestamp")).longValue());
            }
            position.setDevice(device);
            //区域展示处理
            if (StringUtil.isNotBlank(position.getChannelAreaId())) {
                ChannelArea channelArea = channelAreaService.findById(position.getChannelAreaId());
                position.setChannelArea(channelArea);
                if (channelArea != null && !userAreaLevel.equals(channelArea.getLevel())) {
                    channelAreaService.showNameHandle(position.getChannelArea(), userAreaLevel);
                }
            }
        }
        Page<CanCheckPosition> result = new PageImpl<CanCheckPosition>(list, pageable, count);
        return result;
    }

    /**
     * 添加
     *
     * @param agentCode
     * @param status
     * @param showMapInfoStr
     * @time: 2020/10/17 8:52
     * @author: Rock
     * @version 1.0
     */
    public void save(String id, String agentCode, Integer status, String showMapInfoStr) {
        CanCheckPosition ccp = new CanCheckPosition();
        ccp.setId(id);
        ccp.setAgentCode(agentCode);
        ccp.setStatus(status);
        ccp.setShowMapInfoStr(showMapInfoStr);
        mongoTemplate.save(ccp);
    }

    /**
     * @param id
     * @param showMapInfoStr
     * @time: 2020/10/29 16:58
     * @author: Rock
     * @version 1.0
     */
    public void updateShowMapInfoStr(String id, String showMapInfoStr) {
        Update update = new Update();
        update.set("showMapInfoStr", showMapInfoStr);
        this.updateById(id, update);
    }

    /**
     * @time: 2020/10/30 17:26
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> getDistribution(SysUser user) {
        Criteria criteria = Criteria.where("showMapInfoStr").regex(".*?lnglat.*?");
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            criteria.and("agent_code").in(CollectionUtil.longToStr(user.getChannelAff().getChannelCodes()));
        }
        Query query = new Query(criteria);
        List<CanCheckPosition> list = mongoTemplate.find(query, CanCheckPosition.class);
        List<String> result = new ArrayList<>();
        for (CanCheckPosition p : list) {
            result.add(p.getShowMapInfoStr());
        }
        return Response.successResponse(result);
    }

    /**
     * @param position
     * @time: 2020/12/10 15:40
     * @author: Rock
     * @version 1.0
     */
    public void oneAllot(CanCheckPosition position, SysUser user, String ip) {
        if (position != null && StringUtil.isNotBlank(position.getChannelAreaId())) {
            Update update = new Update();
            update.set("channel_area_id", position.getChannelAreaId());
            //更新can_check_position表
            this.updateById(position.getId(), update);
            //更新device表
            deviceService.updateById(position.getId(), update);
            operationService.add(user, ip, "设备位置", "编辑", "号码分配 imei：" + position.getId());
        }
    }

    /**
     * 批量分配
     *
     * @param channelAreaId
     * @param file
     * @param channelAreaIdList
     * @time: 2020/12/11 11:14
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> batchAllot(String channelAreaId, MultipartFile file, SysUser user, String ip) throws Exception {
        //获取当前账号区域级别
        int areaLevel = user.getChannelArea() == null ? 1 : user.getChannelArea().getLevel();
        List<String> channelAreaIdList = new ArrayList<>();
        if (areaLevel > 1) {
            channelAreaIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
        }
        Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(file.getBytes()));
        if (wb != null && wb.getSheetAt(0) != null) {
            Sheet sheet = wb.getSheetAt(0);
            Set<String> set = ExcelUtil.getImei(sheet);
            if (set.size() <= 0) {
                return Response.failedResponse("excel表内无数据");
            }
            int countRow = set.size();
            if (countRow > 20000) {
                return Response.failedResponse("批量分配设备号文件不能超过2W个号码");
            }
            List<String> allotImei = new ArrayList<>();
            List<String> notAllotImei = new ArrayList<>();
            for (String imei : set) {
                if (!RegexUtil.validateDeviceId(imei)) {
                    return Response.failedResponse("存在非法号码：" + imei);
                }
                Device device = deviceService.findById(imei);
                if (device == null) {
                    notAllotImei.add(imei);
                    continue;
                }
                if (areaLevel == 1) {
                    if (!user.getChannelAff().getChannelCodes().contains(device.getAgent())) {
                        notAllotImei.add(imei);
                        continue;
                    }
                } else {
                    if (device.getChannelAreaId() == null || !channelAreaIdList.contains(device.getChannelAreaId())) {
                        notAllotImei.add(imei);
                        continue;
                    }
                }
                allotImei.add(imei);
            }
            if (allotImei.size() > 0) {
                Update update = new Update();
                update.set("channel_area_id", channelAreaId);
                this.updateByIds(allotImei, update);
                deviceService.updateByIds(allotImei, update);
            }
            String msg = "";
            if (allotImei.size() > 0 && notAllotImei.size() > 0) {
                msg = String.format("分配成功%s个号码，失败%s个号码（无权限操作）", allotImei.size(), notAllotImei.size());
            } else if (notAllotImei.size() > 0 && allotImei.size() <= 0) {
                msg = String.format("分配失败%s个号码（无权限操作）", notAllotImei.size());
            } else {
                msg = String.format("分配成功%s个号码", allotImei.size());
            }
            operationService.add(user, ip, "设备位置", "编辑", "号码批量分配: " + msg);
            return Response.successResponse(msg);
        }
        return Response.failedResponse();
    }

    /**
     * @param file
     * @param user
     * @time: 2020/12/12 11:23
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> distribution(MultipartFile file, SysUser user) throws Exception {
        String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
        if (!"xls".equals(fileSuffix.toLowerCase()) && !"xlsx".equals(fileSuffix.toLowerCase())) {
            return Response.failedResponse("请上传excel文件");
        }
        //获取当前账号区域级别
        int areaLevel = user.getChannelArea() == null ? 1 : user.getChannelArea().getLevel();
        List<String> channelAreaIdList = new ArrayList<>();
        if (user.getChannelArea() != null) {
            channelAreaIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
        }
        Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(file.getBytes()));
        if (wb != null && wb.getSheetAt(0) != null) {
            Sheet sheet = wb.getSheetAt(0);
            Set<String> set = ExcelUtil.getImei(sheet);
            if (set.size() <= 0) {
                return Response.failedResponse("excel表内无数据");
            }
            int countRow = set.size();
            if (countRow > 20000) {
                return Response.failedResponse("分配失败，设备号文件不能超过2W个号码");
            }
            List<JSONObject> data = new ArrayList<>();
            int haveLocation = 0;  //有位置
            int notHaveLocation = 0; //无位置
            int notPermission = 0; //无权限
            for (String imei : set) {
                if (!RegexUtil.validateDeviceId(imei)) {
                    return Response.failedResponse("存在非法号码：" + imei);
                }
                Device device = deviceService.findById(imei);
                if (device == null) {
                    notPermission++;
                    continue;
                }
                if (user.getType() == Const.CHANNELUSER_TYPE) {
                    if (areaLevel == 1) {
                        if (!user.getChannelAff().getChannelCodes().contains(device.getAgent())) {
                            notPermission++;
                            continue;
                        }
                    } else {
                        if (device.getChannelAreaId() == null || !channelAreaIdList.contains(device.getChannelAreaId())) {
                            notPermission++;
                            continue;
                        }
                    }
                }
                if (device.getNowloc() != null) {
                    Object lon = device.getNowloc().get("lon");
                    Object lat = device.getNowloc().get("lat");
                    if (StringUtil.isNotBlank(lon) && StringUtil.isNotBlank(lat)) {
                        JSONObject json = new JSONObject();
                        json.put("lnglat", new Object[]{lon, lat});
                        json.put("lnglattime", device.getNowloc().get("timestamp"));
                        json.put("lnglataddress", device.getNowloc().get("address"));
                        if ("1".equals(redisService.hget(imei, "onlineStatus"))) {
                            json.put("name", "设备号: " + imei + " 在线");
                            json.put("style", 0);
                        } else {
                            json.put("name", "设备号: " + imei + " 不在线");
                            json.put("style", 1);
                        }
                        data.add(json);
                        haveLocation++;
                    } else {
                        notHaveLocation++;
                    }
                } else {
                    notHaveLocation++;
                }
            }
            StringBuilder msg = new StringBuilder("查询完成：");
            if (haveLocation > 0) {
                msg.append("有位置").append(haveLocation).append("个号码；");
            }
            if (notHaveLocation > 0) {
                msg.append("无位置").append(notHaveLocation).append("个号码；");
            }
            if (notPermission > 0) {
                msg.append("无权限操作").append(notPermission).append("个号码；");
            }
            return Response.successResponse(data, msg.toString());
        }
        return Response.failedResponse();
    }
}
